﻿using System;
using System.Collections.Generic;
using ProjectDanmaku.Util;
using UnityEngine;

namespace ProjectDanmaku.Entity
{
    public abstract class EntitySubLayer: MonoBehaviour
    {
        public static bool GlobalWorkingState = true;
        
        [SerializeField] [Range(1, 32)] public byte layerBit = 1;
        
        private int _parentSortingOrder;
        public int ParentSortingOrder => _parentSortingOrder;
        
        protected Material Material;
        public readonly List<EntityData> Entities = new ();
        
        public EntityLogicOverride EntityLogicOverride;
        
        public abstract Type GetEntityDataType();

        protected virtual void Awake()
        {
            Material = new Material(Shader.Find("ProjectDanmaku/Entity"));
        }

        protected virtual void Start()
        {
            _parentSortingOrder = transform.parent.GetComponent<EntityLayer>()?.sortingOrder ?? 0;
        }

        private void OnEnable()
        {
            if (layerBit >= 32)
            {
                layerBit = 1;
            }
        }

        public void Tick()
        {
            if (!GlobalWorkingState)
                return;
            if (EntityLogicOverride != null)
            {
                // 防止在 For 循环中做多余的 if 检测.
                foreach (var entity in Entities)
                {
                    if (entity.Active)
                    {
                        EntityLogicOverride.EntityLogicTick(entity);
                        EntityLogicOverride.EntityPhysicsTick(entity);
                        EntityLogicOverride.EntityLateTick(entity);
                    }
                }
                
                return;
            }
            foreach (var entity in Entities)
            {
                if (entity.Active)
                {
                    EntityLogicTick(entity);
                    EntityPhysicsTick(entity);
                    EntityLateTick(entity);
                }
            }
        }

        protected virtual bool CheckOutOfScreen(Vector2 positon)
        {
            return positon.x <= -5.6 || positon.x >= 5.6 || positon.y <= -3.9 || positon.y >= 3.9;
        }

        protected virtual void ApplySpriteToMaterial(Sprite sprite)
        {
            Material.SetTexture("_MainTex", sprite.texture);
        }

        public virtual void AddEntity(EntityData data, bool recycle = true)
        {
            if (recycle)
            {
                int i;
                for (i = 0; i < Entities.Count; i++)
                {
                    if (Entities[i].Destroyed)
                    {
                        Entities[i] = data;
                        break;
                    }
                }
                
                if (i == Entities.Count)
                    Entities.Add(data);
            }
            else
            {
                Entities.Add(data);
            }
            
            if (EntityLogicOverride != null)
                EntityLogicOverride.EntityInit(data);
            else
                EntityInit(data);
        }
        
        public abstract Mesh GetSpriteMesh();

        public virtual Material GetMaterial()
        {
            return Material;
        }
        
        protected abstract void EntityLogicTick(EntityData data);
        protected abstract void EntityPhysicsTick(EntityData data);
        protected abstract void EntityLateTick(EntityData data);
        protected abstract void EntityInit(EntityData data);
    }
}